package com.hqd.ch03.v23.aop.support;

import com.hqd.ch03.v23.aop.IntroductionInfo;
import com.hqd.ch03.v23.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.ClassUtils;

import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class IntroductionInfoSupport implements IntroductionInfo {
    /**
     * 记录类实现的接口
     */
    protected final Set<Class<?>> publishedInterfaces = new LinkedHashSet<>();

    /**
     * 记录对应的接口方法
     */
    private transient Map<Method, Boolean> rememberedMethods = new ConcurrentHashMap<>(32);

    public void suppressInterface(Class<?> ifc) {
        this.publishedInterfaces.remove(ifc);
    }

    protected void implementInterfacesOnObject(Object delegate) {
        this.publishedInterfaces.addAll(ClassUtils.getAllInterfaces(delegate.getClass()));
    }

    /**
     * 检查是否实现该接口
     *
     * @param ifc
     * @return
     */
    public boolean implementsInterface(Class<?> ifc) {
        for (Class<?> pubIfc : this.publishedInterfaces) {
            if (ifc.isInterface() && ifc.isAssignableFrom(pubIfc)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否是增强接口对于方法
     *
     * @param mi
     * @return
     */
    protected final boolean isMethodOnIntroducedInterface(MethodInvocation mi) {
        Boolean rememberedResult = this.rememberedMethods.get(mi.getMethod());
        if (rememberedResult != null) {
            return rememberedResult;
        } else {
            boolean result = implementsInterface(mi.getMethod().getDeclaringClass());
            this.rememberedMethods.put(mi.getMethod(), result);
            return result;
        }
    }

    @Override
    public Class<?>[] getInterfaces() {
        return publishedInterfaces.toArray(new Class[]{});
    }
}
